<?php
namespace app\common;

use think\facade\Log;
use Workerman\Autoloader;
use Workerman\Worker as BaseWorker;
use Workerman\Lib\Timer;

class Worker extends BaseWorker 
{
    public static $progressWorkerList = [];
    public static $progressControllerWorker = null;
    public static $channelWorker = null;

    public static $mimeTypeMap = [];


    protected static $_progressWorkerPidMap = [];

    protected static $_clientConnentions = [];


    public $uniqid = null;

    /**
     * Get all pids of worker processes.
     *
     * @return array
     */
    protected static function getAllWorkerPids()
    {
        $pid_array = array();
        foreach (static::$_pidMap as $worker_pid_array) {
            foreach ($worker_pid_array as $worker_pid) {
                $pid_array[$worker_pid] = $worker_pid;
                Log::debug('o pid :'.$worker_pid);
            }
        }

        foreach (static::$_progressWorkerPidMap as $worker_pid) {
            $pid_array[$worker_pid] = $worker_pid;
            Log::debug('p pid :'.$worker_pid);
        }
        return $pid_array;


    }

    public function getPWorkerPids()
    {
        $pid_array = array();
        foreach (static::$_progressWorkerPidMap as $worker_pid) {
            $pid_array[$worker_pid] = $worker_pid;
            Log::debug('p pid :'.$worker_pid);
        }
        return $pid_array;
    }

    public function setSocketName($socketname)
    {
        $this->_socketName = $socketname;
    }

    public function reConstruct($socket_name = '', $context_option = array())
    {
        // Save all worker instances.

    
        
        static::$_workers[$this->workerId] = $this;
        static::$_pidMap[$this->workerId]  = array();

        // Get autoload root path.
        $backtrace                = \debug_backtrace();
        $this->_autoloadRootPath = \dirname($backtrace[0]['file']);

        if (static::$_OS === OS_TYPE_LINUX && version_compare(PHP_VERSION,'7.0.0', 'ge')) {
            $php_uname = strtolower(php_uname('s'));
            // If not Mac OS then turn reusePort on.
            if ($php_uname !== 'darwin') {
                $this->reusePort = true;
            }
        }

        // Context for socket.
        if ($socket_name) {
            $this->_socketName = $socket_name;
            $this->parseSocketAddress();
            if (!isset($context_option['socket']['backlog'])) {
                $context_option['socket']['backlog'] = static::DEFAULT_BACKLOG;
            }
            $this->_context = \stream_context_create($context_option);
        }
        
        if (static::$globalEvent) {
            static::$globalEvent->destroy();
            static::$globalEvent = null;
        }
        
        foreach(static::$_workers as $key => $one_worker) {
            if ($key !== $this->workerId) {
                $one_worker->unlisten();
                unset(static::$_workers[$key]);
            }
        }
        
    }

    /**
     * Stop.
     *
     * @return void
     */
    public static function stopAll()
    {
        Log::debug('stop 方法');
        static::$_status = static::STATUS_SHUTDOWN;
        // For master process.
        if (static::$_masterPid === \posix_getpid()) {
            Log::debug('父进程执行 stop 方法');
            static::log("Workerman[" . \basename(static::$_startFile) . "] stopping ...");
            $worker_pid_array = static::getAllWorkerPids();
            Log::debug('父进程要通知的子进程：'.json_encode($worker_pid_array));
            // Send stop signal to all child processes.
            if (static::$_gracefulStop) {
                $sig = SIGTERM;
            } else {
                $sig = SIGINT;
            }
            foreach ($worker_pid_array as $worker_pid) {
                \posix_kill($worker_pid, $sig);
                Log::debug('通知进程：'.$worker_pid.'信号：'.$sig);
                if(!static::$_gracefulStop){
                    Timer::add(static::KILL_WORKER_TIMER_TIME, '\posix_kill', array($worker_pid, SIGKILL), false);
                }
            }
            Timer::add(1, "\\Workerman\\Worker::checkIfChildRunning");
            // Remove statistics file.
            if (\is_file(static::$_statisticsFile)) {
                @\unlink(static::$_statisticsFile);
            }
        } // For child processes.
        else {
            Log::debug('子进程执行 stop 方法');

            $worker_pid_array = static::getPWorkerPids();
            Log::debug('子进程获取自己的产生的子进程'.json_encode($worker_pid_array));
            // Send stop signal to all child processes.
            if (static::$_gracefulStop) {
                $sig = SIGTERM;
            } else {
                $sig = SIGINT;
            }
            foreach ($worker_pid_array as $worker_pid) {
                \posix_kill($worker_pid, $sig);
                Log::debug('通知进程：'.$worker_pid.'信号：'.$sig);
                if(!static::$_gracefulStop){
                    Timer::add(static::KILL_WORKER_TIMER_TIME, '\posix_kill', array($worker_pid, SIGKILL), false);
                }
            }
            Timer::add(1, "\\Workerman\\Worker::checkIfChildRunning");
            // Remove statistics file.
            if (\is_file(static::$_statisticsFile)) {
                @\unlink(static::$_statisticsFile);
            }
            foreach (static::$_workers as $worker) {
                if(!$worker->stopping){
                    $worker->stop();
                    $worker->stopping = true;
                }
            }
            if (!static::$_gracefulStop || ConnectionInterface::$statistics['connection_count'] <= 0) {
                static::$_workers = array();
                if (static::$globalEvent) {
                    static::$globalEvent->destroy();
                }
                exit(0);
            }
        }
    }

    /**
     * Run worker instance.
     *
     * @return void
     */
    public function run()
    {
        //Update process state.
        static::$_status = static::STATUS_RUNNING;

        // Register shutdown function for checking errors.
        \register_shutdown_function(array("\\Workerman\\Worker", 'checkErrors'));

        // Set autoload root path.
        Autoloader::setRootPath($this->_autoloadRootPath);

        // Create a global event loop.

        if (!static::$globalEvent) {
            
            $event_loop_class = static::getEventLoopName();

            static::$globalEvent = new $event_loop_class;

            
            $this->resumeAccept();
        }
        // Reinstall signal.
        static::reinstallSignal();



        // Init Timer.
        Timer::init(static::$globalEvent);

        // Set an empty onMessage callback.
        if (empty($this->onMessage)) {
            $this->onMessage = function () {};
        }

        \restore_error_handler();
        
        // Try to emit onWorkerStart callback.
        if ($this->onWorkerStart) {
            try {
                \call_user_func($this->onWorkerStart, $this);
            } catch (\Exception $e) {
                static::log($e);
                // Avoid rapid infinite loop exit.
                sleep(1);
                exit(250);
            } catch (\Error $e) {
                static::log($e);
                // Avoid rapid infinite loop exit.
                sleep(1);
                exit(250);
            }
        }

        // Main loop.
        static::$globalEvent->loop();
    }

   

}
